package play.modules.googleclosure;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import play.Logger;
import play.Play;
import play.PlayPlugin;
import play.exceptions.UnexpectedException;
import play.vfs.VirtualFile;

import com.google.template.soy.SoyFileSet;
import com.google.template.soy.SoyFileSet.Builder;
import com.google.template.soy.base.SoySyntaxException;
import com.google.template.soy.jssrc.SoyJsSrcOptions;

public class ClosurePlugin extends PlayPlugin{
	 
    private Map<String, ClosureTemplate> templates = new HashMap<String, ClosureTemplate>();
    
	private void scanSoyPath(
			VirtualFile path, 
			List<ClosureTemplate> modifiedTemplates)
	{
		if(path.isDirectory()){
			for(VirtualFile subpath: path.list())
				scanSoyPath(subpath, modifiedTemplates);
		}
		else {
			if(path.getName().endsWith(".soy") && !path.getName().startsWith(".")){
				ClosureTemplate tpl = templates.get(path.getName());

				if(tpl != null){
					if(tpl.timestamp < path.lastModified()){
						modifiedTemplates.add(tpl);
					}
				}
				else {
					tpl = 
						new ClosureTemplate(path.getName(), path);
					tpl.timestamp = path.lastModified();
					templates.put(path.getName(), tpl);
					modifiedTemplates.add(tpl);
				}

			}
		}
	}
	
	private List<ClosureTemplate> scanSoyPaths(){
		List<ClosureTemplate> modifiedTemplates = new ArrayList<ClosureTemplate>();
				
		for(VirtualFile path : Play.templatesPath) {
			scanSoyPath(path, modifiedTemplates);
		}
		
		return modifiedTemplates;
	}

	private void compileSoyTemplates(List<ClosureTemplate> sourceTemplates){
		Builder builder = new Builder();
		
		for(ClosureTemplate tpl : sourceTemplates){
			VirtualFile tplFile = tpl.templateFile;
			VirtualFile tplJs = 
				VirtualFile.open(
					"public/javascripts/" 
            		+ tplFile.getName().substring(
            				0, tplFile.getName().lastIndexOf(".soy")) 
            		+ ".js");
			
			builder.add(tplFile.getRealFile());	
			tpl.jsFile = tplJs;
		}
		
		try {		
			SoyFileSet soyFileSet = builder.build();
			SoyJsSrcOptions options = new SoyJsSrcOptions();
			List<String> res = soyFileSet.compileToJsSrc(options, null);
			
			for(int i=0; i<sourceTemplates.size();i++){
				try {
					ClosureTemplate tpl = sourceTemplates.get(i);
					
	                // emit bytecode to standard class layout as well
	                File f = tpl.jsFile.getRealFile();
	                f.getParentFile().mkdirs();
	                
	                Logger.debug("ClosurePlugin : Soy2JS compiled %s into %s", 
	                		tpl.templateFile.relativePath(), 
	                		tpl.jsFile.relativePath());
	                
	                FileWriter fw = new FileWriter(f);
	                fw.write(res.get(i));
	                fw.close();
	                
	                tpl.timestamp = tpl.jsFile.lastModified();
	            } catch (Exception e) {
	                e.printStackTrace();
	            }				
			}
		}catch(SoySyntaxException ex){
			ex.printStackTrace();
			throw new UnexpectedException("While applying soycompiler: ", ex);
		}
	}
	
	private void scan() {
		List<ClosureTemplate> modifiedTemplates = 
			scanSoyPaths();
		
		if(modifiedTemplates != null && modifiedTemplates.size() != 0){
			Logger.debug("ClosurePlugin : change detected");
			compileSoyTemplates(modifiedTemplates);
		}
	}
	
	@Override
	public void onLoad() {
		Logger.debug("ClosurePlugin : onLoad");
		if(Play.mode != Play.Mode.PROD) scan();
	}

	@Override
	public void detectChange() {
		//Logger.debug("ClosurePlugin : detectChange");		
		if(Play.mode != Play.Mode.PROD) scan();
	}

	
}
